﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Mail;
using System.IO;
using System.Configuration;
using System.Web.Configuration;
using System.Net;
using System.Xml.Serialization;
using DomainModel;
using System.Web;

namespace Utils
{
    public class EmailUtils
    {
        public static EmailResult Send(string from, string to, EmailTemplateType type, string[] templateParamValues, int receiverLoginID)
        {
            return Send(from, to, type, templateParamValues, receiverLoginID, 0, string.Empty, true);
        }

        public static EmailResult Send(string from, string to, EmailTemplateType type, string[] templateParamValues, int receiverLoginID, int senderLoginID)
        {
            return Send(from, to, type, templateParamValues, receiverLoginID, senderLoginID, string.Empty, true);
        }

        public static EmailResult Send(string from, string to, EmailTemplateType type, string[] templateParamValues, int receiverLoginID, int senderLoginID, string bcc, Boolean needLog)
        {
            //get Email template , and get subject, build body
            EmailTemplate template = EmailTemplateUtils.BuildEmailTemplate(Convert.ToInt32(type), templateParamValues);
            //build EmailMessage object
            EmailMessage emailMessage = new EmailMessage(from, to, template.Subject, template.Body.ToEmailHtml(), bcc);
            //send out this EmailMessage
            EmailResult emailResult = new EmailResult { Success = true, ErrorMessage="" };
            if (GlobalUtilities.GetInstance().TestEmail)
            {
                emailResult = EmailService.SendByRemoteServer(emailMessage);
            }
            else
            {
                emailResult = EmailService.Send(emailMessage);
            }
            if (needLog)
            {
                //whenever it's successful or not, log this email
                DataUtils.InsertEmailLog(template.EmailTemplateType, senderLoginID, receiverLoginID, emailMessage, emailResult);
            }
            return emailResult;
        }
    }

    public class EmailService
    {
        //since in local, we can't send out email, we need use the real email server in real production server
        public static EmailResult SendByRemoteServer(EmailMessage message)
        {
            string urlTemplate = "http://juicybasket.com/mail/send?key={0}&from={1}&to={2}&bcc={3}&subject={4}&body={5}";
            string url = string.Format(urlTemplate, GlobalUtilities.GetInstance().BackgroundTaskExecutionKey, 
                HttpUtility.UrlEncode(message.From.ToString()), 
                HttpUtility.UrlEncode(string.Join(";", message.To)), 
                HttpUtility.UrlEncode(string.Join(";", message.BCC)), 
                HttpUtility.UrlEncode(HttpUtility.HtmlEncode(message.Subject)), 
                HttpUtility.UrlEncode(HttpUtility.HtmlEncode(message.Body)));

            try
            {
                WebRequest request = WebRequest.Create(url);
                request.Timeout = 1000 * 20; //20 s
                request.GetResponse();
                return new EmailResult { Success = true, ErrorMessage = "" };
            }
            catch (Exception ex)
            {
                return new EmailResult { Success = false, ErrorMessage = ex.Message + "--" + ex.StackTrace };
            }
        }

        public static EmailResult Send(EmailMessage message)
        {
            return Send(message, false);
        }

        public static EmailResult Send(EmailMessage message, bool enableSsl)
        {
            MailMessage mm = new MailMessage();

            // From
            mm.From = message.From;

            // To
            foreach (var address in message.To)
            {
                mm.To.Add(address);
            }

            if (message.BCC != null && message.BCC.Count > 0)
            {
                foreach (var address in message.BCC)
                {
                    mm.Bcc.Add(address);
                }
            }

            // Subject
            mm.Subject = message.Subject;

            // Body
            mm.Body = message.Body;

            // Reply to
            mm.ReplyTo = message.ReplyTo;

            // Html format
            mm.IsBodyHtml = message.IsHtml;

            // create network credentials
            NetworkCredential credentials = new NetworkCredential(
                GlobalUtilities.GetInstance().EmailCredentialUserName, 
                GlobalUtilities.GetInstance().EmailCredentialPassword);

            // establish smtp connection
            //SmtpClient sc = new SmtpClient(host, port);
            SmtpClient sc = new SmtpClient(GlobalUtilities.GetInstance().EmailServerHost);
            sc.EnableSsl = enableSsl;
            sc.Credentials = credentials;

            // send
            try
            {
                sc.Send(mm);
                return new EmailResult { Success = true, ErrorMessage = "" };
            }
            catch (Exception ex)
            {
                return new EmailResult { Success = false, ErrorMessage = ex.Message + "--" + ex.StackTrace};
            }
        }
    }

    /// <summary>
    /// sending email message: from, to, subject, message, bcc
    /// </summary>
    public class EmailMessage
    {
        public List<MailAddress> To { get; private set; }
        public MailAddress From { get; private set; }
        public string Subject { get; private set; }
        public string Body { get; private set; }
        public bool IsHtml { get; private set; }
        public MailAddress ReplyTo { get; private set; }
        public List<MailAddress> BCC { get; private set; }

        /// <summary>
        /// must have from, to, subject and message, bcc is optional
        /// </summary>
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <param name="subject"></param>
        /// <param name="message"></param>
        /// <param name="bcc"></param>
        public EmailMessage(string from, string to, string subject, string body, string bcc = "", Boolean directMode = false) //directMode means don't change info inside this class
        {
            if (string.IsNullOrEmpty(from) ||
                string.IsNullOrEmpty(to) ||
                string.IsNullOrEmpty(subject) ||
                string.IsNullOrEmpty(body))
            {
                throw new Exception("From/To/Subject/Body can't be empty");
            }

            IsHtml = true;
            From = new MailAddress(from);
            //if is testing, just send to test emaila address
            if (GlobalUtilities.GetInstance().TestEmail && !directMode)
            {
                To = new List<MailAddress>();
                To.Add(new MailAddress(GlobalUtilities.GetInstance().TestEmailTo));
            }
            else
            {
                To = to.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries).Select(x => new MailAddress(x)).ToList();
            }
            //if no bbc specified, bcc it to default
            if (!string.IsNullOrEmpty(bcc))
            {
                BCC = bcc.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries).Select(x => new MailAddress(x)).ToList();
            }
            else
            {
                BCC = new List<MailAddress>();
                BCC.Add(new MailAddress(GlobalUtilities.GetInstance().Email_BCC));
            }
            Subject = subject;
            Body = body;
        }
    }

    public class EmailResult
    {
        /// <summary>
        /// sending email successfully or failed
        /// </summary>
        public Boolean Success { get; internal set; }
        /// <summary>
        /// if success = false, has some error message
        /// </summary>
        public string ErrorMessage { get; internal set; }
    }
}
